package com.mimo.common.configuration.distributed;

import java.time.Duration;
import java.util.Objects;
import java.util.stream.Collectors;

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.mimo.common.configuration.mrlock.aspect.DistributedRedisLockAspect;
import com.mimo.common.configuration.semaphore.aspect.DistributedRedisSemaphoreAspect;

/**
 * 基于资源考虑，目前共用当前应用的同一个RedisProperties
 * 
 * @author Hongyu
 */
@Configuration(proxyBeanMethods = false)
@AutoConfigureAfter(RedisAutoConfiguration.class)
public class DistributedConfiguration {

    private static final int MAX_CONNECTION_SIZE = 128;
    private static final int MAX_RETRY = 3;

    private static final String REDIS_SCHEMA = "redis";
    private static final String REDIS_SSL_SCHEMA = "rediss";

    @Bean
    public RedissonClient redissonClient(RedisProperties properties) {
        Config config = new Config();
        config.setLockWatchdogTimeout(Duration.ofSeconds(10).toMillis());

        if (Objects.nonNull(properties.getCluster())) {
            config.useClusterServers().setSslEnableEndpointIdentification(properties.isSsl());
            config.useClusterServers().setClientName("DistributedRedisLock");
            config.useClusterServers().addNodeAddress(properties.getCluster().getNodes().stream()
                    .map(addr -> String.format("%s://%s", properties.isSsl() ? REDIS_SSL_SCHEMA : REDIS_SCHEMA, addr))
                    .collect(Collectors.toList()).toArray(new String[0]));
            config.useClusterServers().setPassword(properties.getPassword());
            if (Objects.isNull(properties.getCluster().getMaxRedirects())) {
                config.useClusterServers().setRetryAttempts(MAX_RETRY);
            } else {
                config.useClusterServers().setRetryAttempts(properties.getCluster().getMaxRedirects());
            }
        } else {
            config.useSingleServer().setSslEnableEndpointIdentification(properties.isSsl());
            config.useSingleServer().setClientName("DistributedRedisLock");
            config.useSingleServer().setAddress(String.format("%s://%s:%s",
                    properties.isSsl() ? REDIS_SSL_SCHEMA : REDIS_SCHEMA, properties.getHost(), properties.getPort()));
            config.useSingleServer().setPassword(properties.getPassword());
            config.useSingleServer().setDatabase(properties.getDatabase());
            config.useSingleServer().setTimeout((int) properties.getTimeout().toMillis());
            config.useSingleServer().setConnectionPoolSize(MAX_CONNECTION_SIZE); // 考虑到生产可能会暴量，double default value here
        }
        return Redisson.create(config);
    }

    @Bean
    public DistributedRedisLockAspect distributedRedisLockAspect(RedissonClient client) {
        return new DistributedRedisLockAspect(client);
    }

    @Bean
    public DistributedRedisSemaphoreAspect distributedRedisSemaphoreAspect(RedissonClient client) {
        return new DistributedRedisSemaphoreAspect(client);
    }

}
